﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using CRM.Anyleads.ResponseStruct;
using CRM.HttpProxy;
using CRM.Json;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace CRM.Anyleads
{
    public class AnyleadsClient
    {
        private readonly HttpClient _httpClient;
        private readonly ILogger<AnyleadsClient>? _logger;
        private readonly string _apiKey;
        private const string ApiKeyKey = "api_key";
        private const string WebhookPrefix = "/api-product/incoming-webhook/";
        public string Domain { get; set; } = "https://myapiconnect.com";

        private string Url => Domain + WebhookPrefix;

        public AnyleadsClient(HttpClient httpClient, string apiKey)
        {
            _httpClient = httpClient;
            _apiKey = apiKey;
        }
        
        public AnyleadsClient(HttpClient httpClient, AnyleadsOption option, ILogger<AnyleadsClient> logger)
        {
            _httpClient = httpClient;
            _logger = logger;
            _apiKey = option.ApiKey;
        }

        public record CustomResponse(bool State, JArray Employees, string Event);

        /// <summary>
        /// Enrichment data software to find new leads (emails)
        /// 仅支持二级域名
        /// </summary>
        public async Task<AnyleadsResponse<List<EmployeeJson>>> EnrichCompany(string domain)
        {
            var @params = PrepareParams();
            @params.Add(nameof(domain), domain);

            return await PostAsJsonAsync<List<EmployeeJson>>(nameof(EnrichCompany), @params);
        }

        private static bool TryFormatResponse(string resp, out JToken obj, out string error)
        {
            obj = default;
            error = default;
            try
            {
                TryGetJsonWithWebsiteNotWorking(ref resp);

                var token = JToken.Parse(resp);

                var eventMessage = token.Value<JToken>("event");
                if (null != eventMessage)
                {
                    error = eventMessage.ToString();
                    return false;
                }

                var matchToken = token.Value<JToken>("data");
                if (null != matchToken)
                {
                    obj = matchToken;
                    return true;
                }
                
                var matchEmployees = token.Value<JToken>("employees");
                if (null != matchEmployees)
                {
                    obj = matchEmployees;
                    return true;
                }
                else
                {
                    obj = token;
                }

                return true;
            }
            catch (JsonReaderException)
            {
                Console.WriteLine("解析异常" + resp);
            }

            return false;
        }

        private static void TryGetJsonWithWebsiteNotWorking(ref string response)
        {
            if (response.StartsWith("Website not working:"))
                response = response[response.IndexOf('{')..];
        }

        /// <summary>
        /// 驼峰转中划线
        /// </summary>
        /// <param name="old"></param>
        /// <param name="splitter"></param>
        /// <returns></returns>
        private static string CamelToStrike(string old, char splitter = '-')
        {
            var @new = new StringBuilder();
            foreach (var @char in old)
            {
                if (@char is >= 'A' and <= 'Z')
                {
                    @new.Append(splitter);
                    @new.Append(char.ToLower(@char));
                }
                else
                {
                    @new.Append(@char);
                }
            }

            return @new.ToString().Trim(splitter);
        }

        private Dictionary<string, string> PrepareParams() =>
            new()
            {
                {ApiKeyKey, _apiKey},
            };

        public async Task<AnyleadsResponse<List<DomainJson>>> ConvertCompanyNames(string companyName)
        {
            var @params = PrepareParams();
            @params.Add(nameof(companyName), companyName);
            return await PostAsJsonAsync<List<DomainJson>>(nameof(ConvertCompanyNames), @params);
        }

        private async Task<AnyleadsResponse<T>> PostAsJsonAsync<T>(string name, Dictionary<string, string> data)
        {
            _logger?.LogInformation("开始请求： {Url}, post数据：{Data}", Url + CamelToStrike(name), data.ToDictionary(x => CamelToStrike(x.Key, '_'), x => x.Value));
            var httpResponse = await _httpClient.PostAsJsonAsync(Url + CamelToStrike(name),
                data.ToDictionary(x => CamelToStrike(x.Key, '_'), x => x.Value));
            var response = await httpResponse.Content.ReadAsStringAsync();
            var serializer = new JsonSerializer()
            {
                ContractResolver = new PascalPropertyNamesContractResolver()
            };
            var canParse = TryFormatResponse(response, out var obj, out var error);
            return new AnyleadsResponse<T>()
            {
                Success = canParse,
                StatusCode = (int) httpResponse.StatusCode,
                Raw = obj?.ToString(),
                Result = obj != null ? obj.ToObject<T>(serializer) : default,
                Error = error
            };
        }

        /// <summary>
        /// 收集指定url上的数据
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public async Task<AnyleadsResponse<UrlDataJson>> ExtractEmailsFromUrls(string url)
        {
            var @params = PrepareParams();
            @params.Add(nameof(url), url);
            return await PostAsJsonAsync<UrlDataJson>(nameof(ExtractEmailsFromUrls),
                @params);
        }

        public record EmailResponse(bool State, bool IsBusinessEmail, bool IsDisposableEmail);

        /// <summary>
        /// 检测邮箱是否可用
        /// </summary>
        /// <param name="email"></param>
        /// <returns></returns>
        public async Task<AnyleadsResponse<EmailResponse>> VerifyEmailState(string email)
        {
            var @params = PrepareParams();
            @params.Add(nameof(email), email);
            return await PostAsJsonAsync<EmailResponse>(nameof(VerifyEmailState), @params);
        }
    }

    public class AnyleadsHttpClient
    {
        public HttpClient HttpClient;

        public void PostAsync()
        {
            // HttpClient.Pos
        }
    }

    public class AnyleadsResponse<T>
    {
        public bool Success { get; init; }
        public int StatusCode { get; init; }
        public string Error { get; init; }
        public T Result { get; set; }
        public string Raw { get; set; }
    }
}